package tool

import (
	"fmt"
	"sync"

	"openmanus/llm"

	logger "github.com/axcom/ninego/log"
)

/*在ToolCollection结构体中， Tools 和 toolMap 存储的是相同的工具实例，但服务于不同的目的：
1. 1.
   Tools ：这是一个BaseTool类型的切片，按工具添加的顺序存储所有工具。它主要用于：
   - 维护工具添加的原始顺序
   - 提供遍历所有工具的能力
   - 在GetTools()和Cleanup()方法中返回完整工具列表
2. 2.
   toolMap ：这是一个映射（map），键为工具名称，值为工具实例。它主要用于：
   - 提供快速的按名称查找功能
   - 在AddTool()中检查工具是否已存在
   - 在Execute()方法中快速获取要执行的工具
*/
// ToolCollection 工具集合，用于管理多个工具
type ToolCollection struct {
	Tools   []BaseTool
	toolMap map[string]BaseTool
	mu      sync.RWMutex
}

// NewToolCollection 创建新的工具集合
func NewToolCollection(tools ...BaseTool) *ToolCollection {
	tc := &ToolCollection{
		Tools:   make([]BaseTool, 0),
		toolMap: make(map[string]BaseTool),
	}
	tc.AddTools(tools...)
	return tc
}

// AddTool 添加单个工具到集合
func (tc *ToolCollection) AddTool(tool BaseTool) {
	tc.mu.Lock()
	defer tc.mu.Unlock()

	name := tool.Name()
	if _, exists := tc.toolMap[name]; exists {
		logger.Warn("Tool %s already exists in collection, skipping", name)
		return
	}

	// 更新工具列表
	tc.Tools = append(tc.Tools, tool)
	tc.toolMap[name] = tool
}

// AddTools 添加多个工具到集合
func (tc *ToolCollection) AddTools(tools ...BaseTool) {
	for _, tool := range tools {
		tc.AddTool(tool)
	}
}

// RemoveTool 从集合中移除工具
func (tc *ToolCollection) RemoveTool(name string) {
	tc.mu.Lock()
	defer tc.mu.Unlock()

	if _, exists := tc.toolMap[name]; !exists {
		return
	}

	// 从工具列表中移除
	for i, tool := range tc.Tools {
		if tool.Name() == name {
			tc.Tools = append(tc.Tools[:i], tc.Tools[i+1:]...)
			break
		}
	}

	// 从工具映射中移除
	delete(tc.toolMap, name)
}

// GetTool 获取指定名称的工具
func (tc *ToolCollection) GetTool(name string) (BaseTool, bool) {
	tc.mu.RLock()
	defer tc.mu.RUnlock()
	tool, exists := tc.toolMap[name]
	return tool, exists
}

// GetTools 获取所有工具
func (tc *ToolCollection) GetTools() []BaseTool {
	tc.mu.RLock()
	defer tc.mu.RUnlock()
	tools := make([]BaseTool, len(tc.Tools))
	copy(tools, tc.Tools)
	return tools
}

// ToParams 转换为函数调用参数列表
func (tc *ToolCollection) ToParams() []llm.Tool {
	tc.mu.RLock()
	defer tc.mu.RUnlock()
	params := make([]llm.Tool, len(tc.Tools))
	for i, tool := range tc.Tools {
		params[i] = tool.ToParam()
	}
	//fmt.Printf("%#v", params)
	return params
}

// Execute 执行指定名称的工具
func (tc *ToolCollection) Execute(name string, args map[string]interface{}) (*ToolResult, error) {
	tc.mu.RLock()
	tool, exists := tc.toolMap[name]
	tc.mu.RUnlock()

	if !exists {
		return nil, fmt.Errorf("tool %s not found", name)
	}

	logger.Debug("Executing tool: ", name)
	result, err := tool.Execute(args)
	if err != nil {
		logger.Errorf("Error executing tool %s: %v", name, err)
		return nil, err
	}

	return result, nil
}

// Cleanup 清理所有工具资源
func (tc *ToolCollection) Cleanup() error {
	tc.mu.RLock()
	tools := make([]BaseTool, len(tc.Tools))
	copy(tools, tc.Tools)
	tc.mu.RUnlock()

	for _, tool := range tools {
		if err := tool.Cleanup(); err != nil {
			logger.Error("Error cleaning up tool %s: %v", tool.Name(), err)
			// 继续清理其他工具
		}
	}

	return nil
}
